//
//  UIDevice+XL.m
//  campus
//
//  Created by xl on 2019/11/25.
//  Copyright © 2019 xl. All rights reserved.
//

#import "UIDevice+XL.h"
#include <net/if.h>
#include <net/if_dl.h>
#include <sys/utsname.h>
#include <sys/sysctl.h>
#include <sys/socket.h> // Per msqr
#include <CommonCrypto/CommonDigest.h>
#import <LocalAuthentication/LocalAuthentication.h>
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
#import <CoreTelephony/CTCarrier.h>


static NSString *XLKeychainServiceName = @"XLKeychainServiceName";
static NSString *XLUDIDName = @"XLNetworkingUDID";
static NSString *XLPasteboardType = @"XLPasteboardType";

@interface UIDevice(Private)
- (NSString *)localMAC;
@end

@implementation UIDevice (XL)

#pragma mark - Private
- (NSString *) localMAC{
    
    int                 mib[6];
    size_t              len;
    char                *buf;
    unsigned char       *ptr;
    struct if_msghdr    *ifm;
    struct sockaddr_dl  *sdl;
    
    mib[0] = CTL_NET;
    mib[1] = AF_ROUTE;
    mib[2] = 0;
    mib[3] = AF_LINK;
    mib[4] = NET_RT_IFLIST;
    
    if ((mib[5] = if_nametoindex("en0")) == 0) {
        printf("Error: if_nametoindex error\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 1\n");
        return NULL;
    }
    
    if ((buf = malloc(len)) == NULL) {
        printf("Could not allocate memory. error!\n");
        return NULL;
    }
    
    if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
        printf("Error: sysctl, take 2");
        free(buf);
        return NULL;
    }
    
    ifm = (struct if_msghdr *)buf;
    sdl = (struct sockaddr_dl *)(ifm + 1);
    ptr = (unsigned char *)LLADDR(sdl);
    NSString *outstring = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X",
                           *ptr, *(ptr+1), *(ptr+2), *(ptr+3), *(ptr+4), *(ptr+5)];
    free(buf);
    
    return outstring;
}

#pragma mark - Public
- (NSString *)createUUID {
    CFUUIDRef uuid = CFUUIDCreate(NULL);
    CFStringRef string = CFUUIDCreateString(NULL, uuid);
    CFRelease(uuid);
    return (__bridge_transfer NSString *)string;
}

- (NSString *)uuid {
    NSString *key = @"XLNetworkingUUID";
    NSString *uuid = [[NSUserDefaults standardUserDefaults] objectForKey:key];
    if (uuid.length == 0) {
        [[NSUserDefaults standardUserDefaults] setObject:[self createUUID] forKey:key];
        return [[[NSUserDefaults standardUserDefaults] objectForKey:key] copy];
    } else {
        return uuid;
    }
}

- (NSString *) udid {
    NSString *udid = [self getUDID];
    if (udid.length==0) {
        udid = [self uuid];
        [self saveUDID:udid];
    }
    return udid;
}

- (NSString *)macaddress {
    NSString *key = @"macAddress";
    NSString *macAddress = [[NSUserDefaults standardUserDefaults] objectForKey:key];
    if (macAddress.length == 0) {
        macAddress = [self localMAC];
        if (macAddress.length>0){
            [[NSUserDefaults standardUserDefaults] setObject:macAddress forKey:key];
            [[NSUserDefaults standardUserDefaults] setObject:@"" forKey:@"macaddressMD5"];
        }
    }
    return macAddress;
}

- (NSString *) macaddressMD5 {
    NSString *key = @"MACAddressMD5";
    NSString *macid = [[NSUserDefaults standardUserDefaults] objectForKey:key];
    if (macid.length == 0) {
        NSString *macaddress = [[UIDevice currentDevice] macaddress];
        macid = [self md5:macaddress];
        if (!macid){
            macid = @"macaddress_empty";
        }else{
            [[NSUserDefaults standardUserDefaults] setObject:macid forKey:key];
        }
    }
    return macid;
}

- (NSString *)machineType
{
    struct utsname systemInfo;
    uname(&systemInfo);
    NSString *machineType = [NSString stringWithCString:systemInfo.machine encoding:NSUTF8StringEncoding];
    NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"iPhoneTypeDefine" ofType:@"plist"];
    NSDictionary *dictionary = [NSDictionary dictionaryWithContentsOfFile:plistPath];
    NSString *type = dictionary[machineType];
    if (type) {
        return type;
    } else {
        return machineType;
    }
}

- (NSString *)machineOperator {
    //获取本机运营商名称
    CTTelephonyNetworkInfo *info = [[CTTelephonyNetworkInfo alloc] init];
    if (@available(iOS 12.0, *)) {
        NSDictionary *dict = info.serviceSubscriberCellularProviders;
        NSString *result = @"NONE";
        NSMutableArray *temArr = [NSMutableArray array];
        [dict enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, CTCarrier *obj, BOOL * _Nonnull stop) {
            if (obj.isoCountryCode.length) {
                NSString *netWorkCode = obj.mobileNetworkCode;
                if ([netWorkCode isEqualToString:@"00"] ||
                    [netWorkCode isEqualToString:@"02"] ||
                    [netWorkCode isEqualToString:@"07"] ||
                    [netWorkCode isEqualToString:@"08"]) {
                    [temArr addObject:@"CMCC"];
                } else if ([netWorkCode isEqualToString:@"01"] ||
                           [netWorkCode isEqualToString:@"06"] ||
                           [netWorkCode isEqualToString:@"09"]) {
                    [temArr addObject:@"CUCC"];
                } else if ([netWorkCode isEqualToString:@"03"] ||
                           [netWorkCode isEqualToString:@"05"] ||
                           [netWorkCode isEqualToString:@"11"]) {
                    [temArr addObject:@"CTCC"];
                }
            }
        }];
        if (temArr.count > 0) {
            result = [temArr componentsJoinedByString:@","];
        }
        return result;
    } else {
        CTCarrier *carrier = [info subscriberCellularProvider];
        NSString *netWorkCode = carrier.mobileNetworkCode;
        NSString *countryCode = carrier.mobileCountryCode;
        if ([countryCode isEqualToString:@"460"]) {
            if ([netWorkCode isEqualToString:@"00"] ||
                [netWorkCode isEqualToString:@"02"] ||
                [netWorkCode isEqualToString:@"07"] ||
                [netWorkCode isEqualToString:@"08"]) {
                return @"CMCC";
            } else if ([netWorkCode isEqualToString:@"01"] ||
                       [netWorkCode isEqualToString:@"06"] ||
                       [netWorkCode isEqualToString:@"09"]) {
                return @"CUCC";
            } else if ([netWorkCode isEqualToString:@"03"] ||
                       [netWorkCode isEqualToString:@"05"] ||
                       [netWorkCode isEqualToString:@"11"]) {
                return @"CTCC";
            } else {
                return @"NONE";
            }
        } else {
            return @"NONE";
        }
    }
}

- (NSString *)machineLocalIP {
    NSString *address = @"error";
    struct ifaddrs *interfaces = NULL;
    struct ifaddrs *temp_addr = NULL;
    int success = 0;
    // 检索当前接口,在成功时,返回0
    success = getifaddrs(&interfaces);
    if (success == 0) {
        // 循环链表的接口
        temp_addr = interfaces;
        while(temp_addr != NULL) {
            // 开热点时本机的IP地址
            if ([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"bridge100"]) {
                address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
            }
            if(temp_addr->ifa_addr->sa_family == AF_INET) {
                // 检查接口是否en0 wifi连接在iPhone上
                if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) {
                    // 得到NSString从C字符串
                    address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)];
                }
                
            }
            temp_addr = temp_addr->ifa_next;
        }
        
    }
    // 释放内存
    freeifaddrs(interfaces);
    return address;
}

- (NSString *)machineNetType {
       UIApplication *app = [UIApplication sharedApplication];
        id statusBar = nil;
    //    判断是否是iOS 13
        NSString *network = @"";
        if (@available(iOS 13.0, *)) {
            UIStatusBarManager *statusBarManager = [UIApplication sharedApplication].keyWindow.windowScene.statusBarManager;
            
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wundeclared-selector"
            if ([statusBarManager respondsToSelector:@selector(createLocalStatusBar)]) {
                UIView *localStatusBar = [statusBarManager performSelector:@selector(createLocalStatusBar)];
                if ([localStatusBar respondsToSelector:@selector(statusBar)]) {
                    statusBar = [localStatusBar performSelector:@selector(statusBar)];
                }
            }
    #pragma clang diagnostic pop
            
            if (statusBar) {
    //            UIStatusBarDataCellularEntry
                id currentData = [[statusBar valueForKeyPath:@"_statusBar"] valueForKeyPath:@"currentData"];
                id _wifiEntry = [currentData valueForKeyPath:@"wifiEntry"];
                id _cellularEntry = [currentData valueForKeyPath:@"cellularEntry"];
                if (_wifiEntry && [[_wifiEntry valueForKeyPath:@"isEnabled"] boolValue]) {
    //                If wifiEntry is enabled, is WiFi.
                    network = @"WIFI";
                } else if (_cellularEntry && [[_cellularEntry valueForKeyPath:@"isEnabled"] boolValue]) {
                    NSNumber *type = [_cellularEntry valueForKeyPath:@"type"];
                    if (type) {
                        switch (type.integerValue) {
                            case 0:
    //                            无sim卡
                                network = @"NONE";
                                break;
                            case 1:
                                network = @"1G";
                                break;
                            case 4:
                                network = @"3G";
                                break;
                            case 5:
                                network = @"4G";
                                break;
                            default:
    //                            默认WWAN类型
                                network = @"WWAN";
                                break;
                                }
                            }
                        }
                    }
        }else {
            statusBar = [app valueForKeyPath:@"statusBar"];
            
            if (SAFEAREA_BOTTOM_HEIGHT > 0) {
    //            刘海屏
                    id statusBarView = [statusBar valueForKeyPath:@"statusBar"];
                    UIView *foregroundView = [statusBarView valueForKeyPath:@"foregroundView"];
                    NSArray *subviews = [[foregroundView subviews][2] subviews];
                    
                    if (subviews.count == 0) {
    //                    iOS 12
                        id currentData = [statusBarView valueForKeyPath:@"currentData"];
                        id wifiEntry = [currentData valueForKey:@"wifiEntry"];
                        if ([[wifiEntry valueForKey:@"_enabled"] boolValue]) {
                            network = @"WIFI";
                        }else {
    //                    卡1:
                            id cellularEntry = [currentData valueForKey:@"cellularEntry"];
    //                    卡2:
                            id secondaryCellularEntry = [currentData valueForKey:@"secondaryCellularEntry"];

                            if (([[cellularEntry valueForKey:@"_enabled"] boolValue]|[[secondaryCellularEntry valueForKey:@"_enabled"] boolValue]) == NO) {
    //                            无卡情况
                                network = @"NONE";
                            }else {
    //                            判断卡1还是卡2
                                BOOL isCardOne = [[cellularEntry valueForKey:@"_enabled"] boolValue];
                                int networkType = isCardOne ? [[cellularEntry valueForKey:@"type"] intValue] : [[secondaryCellularEntry valueForKey:@"type"] intValue];
                                switch (networkType) {
                                        case 0://无服务
                                        network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"NONE"];
                                        break;
                                        case 3:
                                        network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"2G/E"];
                                        break;
                                        case 4:
                                        network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"3G"];
                                        break;
                                        case 5:
                                        network = [NSString stringWithFormat:@"%@-%@", isCardOne ? @"Card 1" : @"Card 2", @"4G"];
                                        break;
                                    default:
                                        break;
                                }
                                
                            }
                        }
                    
                    }else {
                        
                        for (id subview in subviews) {
                            if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarWifiSignalView")]) {
                                network = @"WIFI";
                            }else if ([subview isKindOfClass:NSClassFromString(@"_UIStatusBarStringView")]) {
                                network = [subview valueForKeyPath:@"originalText"];
                            }
                        }
                    }
                    
                }else {
    //                非刘海屏
                    UIView *foregroundView = [statusBar valueForKeyPath:@"foregroundView"];
                    NSArray *subviews = [foregroundView subviews];
                    
                    for (id subview in subviews) {
                        if ([subview isKindOfClass:NSClassFromString(@"UIStatusBarDataNetworkItemView")]) {
                            int networkType = [[subview valueForKeyPath:@"dataNetworkType"] intValue];
                            switch (networkType) {
                                case 0:
                                    network = @"NONE";
                                    break;
                                case 1:
                                    network = @"2G";
                                    break;
                                case 2:
                                    network = @"3G";
                                    break;
                                case 3:
                                    network = @"4G";
                                    break;
                                case 5:
                                    network = @"WIFI";
                                    break;
                                default:
                                    break;
                            }
                        }
                    }
                }
        }

        if ([network isEqualToString:@""]) {
            network = @"NO DISPLAY";
        }
        return network;
}


- (BOOL)isJailbreak
{
    //由于iOS9以后出现白名单，造成控制台不断打印警告
    //所以换成以下方式判断
    NSArray *paths = @[@"/Applications/Cydia.app",
                       @"/private/var/lib/apt/",
                       @"/private/var/lib/cydia",
                       @"/private/var/stash"];
    for (NSString *path in paths) {
        if ([[NSFileManager defaultManager] fileExistsAtPath:path]) return YES;
    }
    
    FILE *bash = fopen("/bin/bash", "r");
    if (bash != NULL) {
        fclose(bash);
        return YES;
    }
    
    NSString *path = [NSString stringWithFormat:@"/private/%@", [self getUDID]];
    if ([@"test" writeToFile : path atomically : YES encoding : NSUTF8StringEncoding error : NULL]) {
        [[NSFileManager defaultManager] removeItemAtPath:path error:nil];
        return YES;
    }
    return NO;
}

- (BOOL)getProxyStatus
{
    NSDictionary*proxySettings = (__bridge NSDictionary*)(CFNetworkCopySystemProxySettings());
    NSArray *proxies = (__bridge NSArray *)(CFNetworkCopyProxiesForURL((__bridge CFURLRef _Nonnull)([NSURL URLWithString:@"http://www.xiaolian365.com"]), (__bridge CFDictionaryRef _Nonnull)(proxySettings)));

    NSDictionary*settings = [proxies objectAtIndex:0];
    NSLog(@"host=%@", [settings objectForKey:(NSString*)kCFProxyHostNameKey]);
    NSLog(@"port=%@", [settings objectForKey:(NSString*)kCFProxyPortNumberKey]);
    NSLog(@"type=%@", [settings objectForKey:(NSString*)kCFProxyTypeKey]);
    
    if([[settings objectForKey:(NSString *)kCFProxyTypeKey] isEqualToString:@"kCFProxyTypeNone"]){
        return NO;
        
    }else{
        return YES;
    }

}

#pragma mark - UDID相关
- (NSString *)getUDID {
    NSData *udidData = [self searchKeychainCopyMatching:XLUDIDName];
    NSString *udid = nil;
    if (udidData != nil) {
        NSString *temp = [[NSString alloc] initWithData:udidData encoding:NSUTF8StringEncoding];
        udid = [NSString stringWithFormat:@"%@", temp];
    }
    if (udid.length == 0) {
        udid = [self readPasteBoradforIdentifier:XLUDIDName];
    }
    return udid;
}

#pragma mark - UDID相关
- (void)saveUDID:(NSString *)udid {
    BOOL saveOk = NO;
    NSData *udidData = [self searchKeychainCopyMatching:XLUDIDName];
    if (udidData == nil) {
        saveOk = [self createKeychainValue:udid forIdentifier:XLUDIDName];
    } else {
        saveOk = [self updateKeychainValue:udid forIdentifier:XLUDIDName];
    }
    if (!saveOk) {
        [self createPasteBoradValue:udid forIdentifier:XLUDIDName];
    }
}

- (NSMutableDictionary *)newSearchDictionary:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [[NSMutableDictionary alloc] init];
    
    [searchDictionary setObject:(__bridge id)kSecClassGenericPassword forKey:(__bridge id)kSecClass];
    
    NSData *encodedIdentifier = [identifier dataUsingEncoding:NSUTF8StringEncoding];
    [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrGeneric];
    [searchDictionary setObject:encodedIdentifier forKey:(__bridge id)kSecAttrAccount];
    [searchDictionary setObject:XLKeychainServiceName forKey:(__bridge id)kSecAttrService];
    
    return searchDictionary;
}

- (NSData *)searchKeychainCopyMatching:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    
    // Add search attributes
    [searchDictionary setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit];
    
    // Add search return types
    [searchDictionary setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData];
    
    CFDataRef result = nil;
    SecItemCopyMatching((__bridge CFDictionaryRef)searchDictionary,
                        (CFTypeRef *)&result);
    
    return (__bridge NSData *)result;
}

- (BOOL)createKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
    NSMutableDictionary *dictionary = [self newSearchDictionary:identifier];
    
    NSData *passwordData = [value dataUsingEncoding:NSUTF8StringEncoding];
    [dictionary setObject:passwordData forKey:(__bridge id)kSecValueData];
    
    OSStatus status = SecItemAdd((__bridge CFDictionaryRef)dictionary, NULL);
    
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}

- (BOOL)updateKeychainValue:(NSString *)value forIdentifier:(NSString *)identifier {
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    NSMutableDictionary *updateDictionary = [[NSMutableDictionary alloc] init];
    NSData *passwordData = [value dataUsingEncoding:NSUTF8StringEncoding];
    [updateDictionary setObject:passwordData forKey:(__bridge id)kSecValueData];
    
    OSStatus status = SecItemUpdate((__bridge CFDictionaryRef)searchDictionary,
                                    (__bridge CFDictionaryRef)updateDictionary);
    if (status == errSecSuccess) {
        return YES;
    }
    return NO;
}

- (void)deleteKeychainValue:(NSString *)identifier {
    
    NSMutableDictionary *searchDictionary = [self newSearchDictionary:identifier];
    SecItemDelete((__bridge CFDictionaryRef)searchDictionary);
}

- (void)createPasteBoradValue:(NSString *)value forIdentifier:(NSString *)identifier {
    UIPasteboard *pb = [UIPasteboard pasteboardWithName:XLKeychainServiceName create:YES];
    NSDictionary *dict = [NSDictionary dictionaryWithObject:value forKey:identifier];
    NSData *dictData = [NSKeyedArchiver archivedDataWithRootObject:dict];
    [pb setData:dictData forPasteboardType:XLPasteboardType];
}

- (NSString *)readPasteBoradforIdentifier:(NSString *)identifier {
    UIPasteboard *pb = [UIPasteboard pasteboardWithName:XLKeychainServiceName create:YES];
    NSDictionary *dict = [NSKeyedUnarchiver unarchiveObjectWithData:[pb dataForPasteboardType:XLPasteboardType]];
    return [dict objectForKey:identifier];
}

- (NSString *)md5:(NSString *)string {
    NSData* inputData = [string dataUsingEncoding:NSUTF8StringEncoding];
    unsigned char outputData[CC_MD5_DIGEST_LENGTH];
    CC_MD5([inputData bytes], (unsigned int)[inputData length], outputData);
    
    NSMutableString* hashStr = [NSMutableString string];
    int i = 0;
    for (i = 0; i < CC_MD5_DIGEST_LENGTH; ++i)
        [hashStr appendFormat:@"%02x", outputData[i]];
    
    return hashStr;
}

/** 判断当前手机是否支持指纹解锁 */
- (BOOL)isCurrentSupportTouchId {
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;
    BOOL supportEvaluatePolicy = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
    if (supportEvaluatePolicy) {
        if (@available(iOS 11.0, *)) {
            if (context.biometryType == LABiometryTypeTouchID) {
                return YES;
            } else {
                return NO;
            }
        } else {
            // Fallback on earlier versions
            return NO;
        }
    } else {
        return NO;
    }
}
/** 判断当前手机是否支持人脸识别解锁 */
- (BOOL)isCurrentSupportFaceId {
    LAContext *context = [[LAContext alloc] init];
    NSError *error = nil;
    BOOL supportEvaluatePolicy = [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error];
    if (supportEvaluatePolicy) {
        if (@available(iOS 11.0, *)) {
            if (context.biometryType == LABiometryTypeFaceID) {
                return YES;
            } else {
                return NO;
            }
        } else {
            // Fallback on earlier versions
            return NO;
        }
    } else {
        return NO;
    }
}

@end
